package com.filetest.service;

import com.filetest.mapper.FileMapper;
import com.filetest.model.FileMetadata;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author xhw
 */
@Service
public class FileService {

    @Autowired
    private FileMapper fileMapper;

    @Autowired
    private FileService(FileMapper fileMapper) {
        this.fileMapper = fileMapper;
    }

    //上传
    @Value("${file.upload-dir}")
    private String uploadDir;
    //保存文件的元数据到数据库，保存文件内容到本地系统
    public FileMetadata saveFile(MultipartFile file, Integer userId, String logicPath) throws IOException {
        String normalizedPath = PathUtils.normalizePath(logicPath);
        //分割路径，以处理目录结构
        String[] pathParts = normalizedPath.split("/");


        //构建目录路径
        String userDirPath = uploadDir + "/" + userId;
        StringBuilder currentPath = new StringBuilder();


        //按路径部分构建子目录,从1开始排除根目录
        for (int i = 1; i < pathParts.length - 1; i++) {
            currentPath.append("/").append(pathParts[i]);
            String dirPath = currentPath.toString();
            File directory = new File(userDirPath, dirPath);

            if (!directory.exists() && !directory.mkdirs()) {
                throw new IOException("无法创建目录：" + directory.getPath());
            }

            //检查元数据是否已经存在数据库中，如果不存在，则保存该目录的元数据
            String dbPath = dirPath; // 确保路径前有斜杠
            if (fileMapper.findByUserIdAndPath(userId, dbPath) == null) {
                //若不存在，创建目录元数据并保存到数据库
                FileMetadata dirMetadata = new FileMetadata();
                dirMetadata.setUserId(userId);
                dirMetadata.setPath(dbPath);
                //根目录的depth为1，每增加一个子目录，depth加1
                dirMetadata.setDepth(PathUtils.calculateDepth(dbPath));
                dirMetadata.setType("");
                dirMetadata.setSize(0);
                dirMetadata.setUploadTime(new Timestamp(System.currentTimeMillis()));

                fileMapper.insert(dirMetadata);
            }
        }

        //处理文件名，将文件保存至最后一级目录
        String filename = pathParts[pathParts.length - 1];
        File targetFile = new File(userDirPath + currentPath.toString(), filename);

        //保存文件到文件系统
        try (InputStream inputStream = file.getInputStream();
             OutputStream outputStream = new FileOutputStream(targetFile)) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }

        //提取文件后缀名，如果存在
        String type = "";
        int dotIndex = filename.lastIndexOf(".");
        if (dotIndex > 0) {
            type = filename.substring(dotIndex + 1);
        }

        //构建文件元数据并保存到数据库
        FileMetadata fileMetadata = new FileMetadata();
        fileMetadata.setUserId(userId);
        //添加原始的逻辑路径
        fileMetadata.setPath(logicPath);
        fileMetadata.setDepth(PathUtils.calculateDepth(logicPath));
        fileMetadata.setType(type);
        fileMetadata.setSize((int) file.getSize());
        fileMetadata.setUploadTime(new Timestamp(System.currentTimeMillis()));
        fileMapper.insert(fileMetadata);
        return fileMetadata;
    }


    //查询所有文件
    public List<FileMetadata> listChildren(Integer userId, String logicPath) {
        String normalizedPath = PathUtils.normalizePath(logicPath);
        int currentDepth = PathUtils.calculateDepth(normalizedPath);

        if (normalizedPath.equals("/Root")) {
            return fileMapper.findRootFilesByUserId(userId);
        } else {
            return fileMapper.findFilesByPathAndDepth(userId, normalizedPath, currentDepth + 1);
        }
    }


    //查询单个文件
    public FileMetadata getFileDetails(Integer userId, String logicPath) {
        String normalizedPath = PathUtils.normalizePath(logicPath);

        //查询数据库获取目录元数据
        FileMetadata fileMetadata = fileMapper.findByUserIdAndPath(userId, normalizedPath);

        //如果文件存在就返回元数据
        if (fileMetadata != null) {
            return fileMetadata;
        } else {
            //如果找不到文件，返回null
            return null;
        }
    }

    //删除目录
    public void deleteFile(Integer userId, String logicPath) throws IOException {
        String normalizedPath = PathUtils.normalizePath(logicPath);

        // 查找数据库中是否有对应的文件或目录记录
        FileMetadata fileMetadata = fileMapper.findByUserIdAndPath(userId, normalizedPath);
        if (fileMetadata == null) {
            throw new IOException("文件或目录不存在：" + logicPath);
        }

        // 获取文件或目录在文件系统中的存储路径
        File fileToDelete = new File(uploadDir + File.separator + userId + normalizePathForFileSystem(normalizedPath));

        // 检查目标是否存在，并尝试删除
        if (fileToDelete.exists()) {
            boolean deleteSuccess = fileToDelete.delete(); // 尝试删除文件或空目录
            if (!deleteSuccess) {
                // 如果删除失败（比如因为目录非空），抛出异常
                throw new IOException("无法删除文件或目录：" + fileToDelete.getAbsolutePath());
            }
        } else {
            // 如果文件或目录在文件系统中不存在，也视为异常情况
            throw new FileNotFoundException("文件或目录在文件系统中未找到：" + fileToDelete.getAbsolutePath());
        }

        // 从数据库删除与文件或目录关联的记录
        fileMapper.deleteByUserIdAndPath(userId, normalizedPath);
    }

    private String normalizePathForFileSystem(String logicPath) {
        return logicPath.replaceFirst("^/ROOT:", "").replace(":", File.separator);
    }

    //下载文件
    public void downloadFile(Integer userId, String logicPath, HttpServletResponse response) throws IOException {
        String fullName = uploadDir + File.separator + userId + File.separator + logicPath;
        File file = new File(fullName);
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在");
        }
        //设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
        //使用IO流输出文件
        try (InputStream inputStream = new FileInputStream(file);
             OutputStream outputStream = response.getOutputStream()) {
            byte[] buffer = new byte[4096];
            int bufferRead;
            while ((bufferRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bufferRead);
            }
        }
    }


    //构建下载文件的路径并且返回一个FileSystemResource
    public FileSystemResource getFileSystemResource(Integer userId, String logicPath) {
        //构建文件路径
        Path filePath = Paths.get(uploadDir, userId.toString(), logicPath);
        //使用Spring的FileSystemResource来包装文件
        FileSystemResource file = new FileSystemResource(filePath.toFile());
        return file;
    }

    //构建一个下载文件的URL
    public String createDownloadUrl(Integer userId, String logicPath) {
        return ServletUriComponentsBuilder.fromCurrentContextPath()
                .path("/file/download/")
                .path(userId.toString())
                .path("/")
                .pathSegment(logicPath.split("/"))
                .build().toUriString();
    }

}
